package br.com.programacao.concorrente.problema;

import br.com.programacao.concorrente.auxiliar.Constantes;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import java.util.concurrent.Semaphore;

/**
 * A classe Buffer é responsável por ter os métodos que irão remover os itens
 * além de popular o próprio buffer na inicialização do sistema.
 */
public class Buffer {

    private Map<String, File> mapa;
    private List<String> chaves;
    private boolean lock = false;
    private static Buffer instance = null;

    static {
        instance = new Buffer();
    }

    /**
     * Em toda a aplicação é permitido haver apenas uma instancia do buffer. E
     * nesta instancia que todos os consumidores irão obter seus arquivos.
     *
     * @return Instance buffer
     */
    public static Buffer getInstance() {
        return Buffer.instance;
    }

    /**
     * Construtor privado do Buffer. Durante sua contrução já é criado o mapa.
     *
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     */
    private Buffer() {
        this.mapa = new HashMap<>();
        this.chaves = new ArrayList<>();
    }

    /**
     * Retorna o arquivo para chave, removendo o elemento do mapa(buffer). Toda
     * a remoção do buffer é dada de forma sequencial a partir da chave.
     *
     * @param chave
     * @return File
     */
    public synchronized File getFile(String chave) {
        System.out.println("removeu" + chave);
        return mapa.remove(chave);
    }

    /**
     * Retorna a proxima chave valida do buffer.
     *
     * @return chave
     */
    public synchronized String getNextKey() throws InterruptedException {
        String retorno = null;
        retorno = this.chaves.remove(0);
        return retorno;
    }

    public synchronized int getSize() {
        return mapa.size();
        //return chaves.size();
    }

    /**
     * Metodo responsavel por alimentar o buffer.
     *
     * @param file
     * @throws Exception informa que o arquivo enviado é nulo
     */
    public synchronized void setFile(File file) throws Exception {
        setFileWithTest(file);
    }

    /**
     * Metodo para fazer as validações necessárias para incluir o arquivo
     * @param file
     * @throws Exception 
     */
    private void setFileWithTest(File file) throws Exception {
        if (file != null) {
            mapa.put(file.getName(), file);
            this.chaves.add(file.getName());
        } else {
            throw new Exception("File is null");
        }
    }

    /**
     * Verifica se o buffer está cheio.
     * @return 
     */
    public synchronized boolean isFull() {
        return getSize() >= Constantes.TAM_MAX_BUFFER;
    }

}
